// --------------------------------------------------------------------------------------------------------------------
// <copyright file="CompareOption.cs" company="SmartPlan">
//   SmartPlan 2011
// </copyright>
// <summary>
//   The compare option.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace DbDiff.Common.Comparer
{
    using System;
    using System.IO;
    using System.Runtime.Serialization;
    using System.Text;
    using System.Xml;
    using Helper;

    /// <summary>
    /// The compare option.
    /// </summary>
    [DataContract]
    public class CompareOption
    {

        #region Fields & properties

        /// <summary>
        /// The controlled by.
        /// </summary>
        [DataMember]
        private string controlledBy;

        /// <summary>
        /// The error message.
        /// </summary>
        [DataMember]
        private string errorMessage;

        /// <summary>
        /// The label.
        /// </summary>
        [DataMember]
        private string label;

        /// <summary>
        /// The recompare.
        /// </summary>
        [DataMember]
        private bool recompare;

        /// <summary>
        /// The reload.
        /// </summary>
        [DataMember]
        private bool reload;

        /// <summary>
        /// The types.
        /// </summary>
        [DataMember]
        private string[] types;

        /// <summary>
        /// The ui type.
        /// </summary>
        [DataMember]
        private string uiType;

        /// <summary>
        /// The visible.
        /// </summary>
        [DataMember]
        private bool visible;

        /// <summary>
        ///   Gets or sets OptionName.
        /// </summary>
        [DataMember]
        private string optionName;

        /// <summary>
        ///   Gets or sets RowName.
        /// </summary>
        [DataMember]
        private string rowName;

        /// <summary>
        /// The value of the option
        /// </summary>
        [DataMember]
        private string value;

        /// <summary>
        /// Error message id
        /// </summary>
        [DataMember]
        private string errorMsgId;

        /// <summary>
        /// Table name
        /// </summary>
        [DataMember]
        private string tableName;

        /// <summary>
        /// The Tool tip
        /// </summary>
        [DataMember]
        private string toolTip;

        /// <summary>
        /// Compare option typ
        /// </summary>
        [DataMember]
        private OptionType compareOptionType;

        /// <summary>
        /// Control type
        /// </summary>
        [DataMember]
        private CompareOptionControlType compareOptionControlType;

        /// <summary>
        /// Row number
        /// </summary>
        [DataMember]
        private int rowNumber;


        #endregion Fields & properties

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="CompareOption"/> class.
        /// </summary>
        /// <param name="param">
        /// The param for compare option
        /// </param>
        public CompareOption(CompareOptionParams param)
        {
            this.CompareOptionInit(
                param.Name,
                param.Value,
                param.CompareOptionType,
                param.ErrorMsgId,
                param.TableName,
                param.ToolTip,
                param.Label,
                param.ErrorMessage,
                param.ControlledBy,
                param.Visible,
                param.Reload,
                param.Recompare,
                param.CompareOptionControlType,
                param.UserInterfaceType,
                param.RowNumber);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="CompareOption"/> class.
        /// </summary>
        /// <param name="name">
        /// The name.
        /// </param>
        /// <param name="value">
        /// The value.
        /// </param>
        /// <param name="compareOptionType">
        /// The compare option type.
        /// </param>
        /// <param name="errorMsgId">
        /// The error msg id.
        /// </param>
        /// <param name="tableName">
        /// The table name.
        /// </param>
        /// <param name="toolTip">
        /// The tool tip.
        /// </param>
        /// <param name="label">
        /// The label.
        /// </param>
        /// <param name="errorMessage">
        /// The error message.
        /// </param>
        /// <param name="controlledBy">
        /// The controlled by.
        /// </param>
        /// <param name="visible">
        /// The visible.
        /// </param>
        /// <param name="reload">
        /// The reload.
        /// </param>
        /// <param name="recompare">
        /// The recompare.
        /// </param>
        /// <param name="compareOptionControlType">
        /// The compare option control type.
        /// </param>
        /// <param name="uiType">
        /// The ui type.
        /// </param>
        /// <param name="rowNumber">
        /// The row number.
        /// </param>
        public CompareOption(string name, string value, OptionType compareOptionType, string errorMsgId,
                             string tableName, string toolTip,
                             string label, string errorMessage, string controlledBy, string visible, string reload,
                             string recompare,
                             CompareOptionControlType compareOptionControlType, string uiType, int rowNumber)
        {
            this.CompareOptionInit(name, value, compareOptionType, errorMsgId, tableName,
                                   toolTip, label, errorMessage, controlledBy, visible,
                                   reload, recompare, compareOptionControlType,
                                   uiType, rowNumber);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="CompareOption"/> class.
        /// </summary>
        /// <param name="configNode">
        /// The config node.
        /// </param>
        public CompareOption(XmlNode configNode)
        {
            this.Init();
            this.SetDataEx(configNode);
        }

        #endregion

        #region properties
        /// <summary>
        ///   Gets the Types.
        /// </summary>        
        public string[] Types
        {
            get { return this.types; }
            private set { this.types = value; }
        }

        /// <summary>
        ///   Gets the ControlledBy.
        /// </summary>
        public string ControlledBy
        {
            get { return this.controlledBy; }
            private set { this.controlledBy = value; }
        }

        /// <summary>
        ///   Gets the ErrorMessage.
        /// </summary>
        public string ErrorMessage
        {
            get { return this.errorMessage; }
            private set { this.errorMessage = value; }
        }

        /// <summary>
        ///   Gets the Label.
        /// </summary>
        public string Label
        {
            get { return this.label; }
            private set { this.label = value; }
        }

        /// <summary>
        ///   Gets a value indicating whether Visible.
        /// </summary>
        public bool Visible
        {
            get { return this.visible; }
            private set { this.visible = value; }
        }

        /// <summary>
        ///   Gets the UIType.
        /// </summary>
        public string UIType
        {
            get { return this.uiType; }
            private set { this.uiType = value; }
        }

        /// <summary>
        ///   Gets a value indicating whether Reload.
        /// </summary>
        public bool Reload
        {
            get { return this.reload; }
            private set { this.reload = value; }
        }

        /// <summary>
        ///   Gets a value indicating whether Recompare.
        /// </summary>
        public bool Recompare
        {
            get { return this.recompare; }
            private set { this.recompare = value; }
        }

        /// <summary>
        ///   Gets the Name.
        /// </summary>
        public string Name
        {
            get { return this.optionName; }
        }

        /// <summary>
        ///   Gets or sets Value.
        /// </summary>        
        public string Value
        {
            get { return this.value; }
            set { this.value = value; }
        }


        /// <summary>
        ///   Gets ErrorMsgId.
        /// </summary>
        public string ErrorMsgId
        {
            get { return this.errorMsgId; }
            private set { this.errorMsgId = value; }
        }

        /// <summary>
        ///   Gets the TableName.
        /// </summary>
        public string TableName
        {
            get { return this.tableName; }
            private set { this.tableName = value; }
        }

        /// <summary>
        ///   Gets the ToolTip.
        /// </summary>
        public string ToolTip
        {
            get { return this.toolTip; }
            private set { this.toolTip = value; }
        }

        /// <summary>
        ///   Gets the CompareOptionType.
        /// </summary>
        public OptionType CompareOptionType
        {
            get { return this.compareOptionType; }
            private set { this.compareOptionType = value; }
        }

        /// <summary>
        ///   Gets the CompareOptionControlType.
        /// </summary>
        public CompareOptionControlType CompareOptionControlType
        {
            get { return this.compareOptionControlType; }
            private set { this.compareOptionControlType = value; }
        }

        /// <summary>
        ///   Gets the RowNumber.
        /// </summary>
        public int RowNumber
        {
            get { return this.rowNumber; }
            private set { this.rowNumber = value; }
        }

        #endregion

        #region public methods

        /// <summary>
        /// The set data ex.
        /// </summary>
        /// <param name="configNode">
        /// The config node.
        /// </param>
        /// <exception cref="ApplicationException">
        /// </exception>
        public void SetDataEx(XmlNode configNode)
        {
            string stringValue;
            try
            {
                this.optionName = XmlHelper.GetAttributeValue(configNode, "Key", true);
                this.Value = XmlHelper.GetAttributeValue(configNode, "Value", string.Empty);
                this.ErrorMsgId = XmlHelper.GetAttributeValue(configNode, "ErrorMsgId", this.Value);
                stringValue = XmlHelper.GetAttributeValue(configNode, "TableName", string.Empty);
                if (stringValue.Trim().Length > 0)
                {
                    this.TableName = stringValue;
                }

                this.rowName = XmlHelper.GetAttributeValue(configNode, "RowName", string.Empty);
                this.ToolTip = XmlHelper.GetAttributeValue(configNode, "ToolTip", string.Empty);

                stringValue = XmlHelper.GetAttributeValue(configNode, "CompareOptionType", 
                                                          OptionType.DatabaseObjectOptions.ToString());
                this.CompareOptionType = (OptionType) Enum.Parse(typeof (OptionType), stringValue, true);

                stringValue = XmlHelper.GetAttributeValue(configNode, "CompareOptionControlType", 
                                                          CompareOptionControlType.TextBox.ToString());
                this.CompareOptionControlType =
                    (CompareOptionControlType) Enum.Parse(typeof (CompareOptionControlType), stringValue, true);

                // EX
                stringValue = XmlHelper.GetAttributeValue(configNode, "TableName", string.Empty);
                this.Types = stringValue.Trim().Length > 0 ? stringValue.Split(new[] {'@'}) : new string[0];
                this.Label = XmlHelper.GetAttributeValue(configNode, "Label", this.Label);
                this.ErrorMessage = XmlHelper.GetAttributeValue(configNode, "ErrorMessage", this.ErrorMessage);
                this.ControlledBy = XmlHelper.GetAttributeValue(configNode, "ControlledBy", this.ControlledBy);
                this.Visible = Convert.ToBoolean(XmlHelper.GetAttributeValue(configNode, "Visible", this.Visible));
                this.UIType = XmlHelper.GetAttributeValue(configNode, "UIType", this.UIType);
                this.Reload = Convert.ToBoolean(XmlHelper.GetAttributeValue(configNode, "Reload", this.Reload));
                this.Recompare = Convert.ToBoolean(XmlHelper.GetAttributeValue(configNode, "Recompare", this.Recompare));

                this.RowNumber =
                    Convert.ToInt32(XmlHelper.GetAttributeValue(configNode, "RowNumber", this.RowNumber.ToString()));
            }
            catch (Exception e)
            {
                throw new ApplicationException("Invalid compareoption configuration!", e);
            }
        }

        /// <summary>
        /// The get xml ex.
        /// </summary>
        /// <returns>
        /// The xml string for save
        /// </returns>
        public string GetXmlEx()
        {
            // xmltextwriter
            string retval = null;
            var memoryStream = new MemoryStream();
            var xmlTextWriter = new XmlTextWriter(memoryStream, Encoding.UTF8);
            this.GetXmlEx(xmlTextWriter);
            xmlTextWriter.Flush();
            memoryStream.Flush();

            memoryStream.Seek(0, SeekOrigin.Begin);
            var bya = new byte[memoryStream.Length];
            memoryStream.Read(bya, 0, (int) memoryStream.Length);
            retval = Encoding.UTF8.GetString(bya);
            memoryStream.Close();
            xmlTextWriter.Close();

            return retval;
        }

        /// <summary>
        /// The get xml ex.
        /// </summary>
        /// <param name="writer">
        /// The writer.
        /// </param>
        public void GetXmlEx(XmlTextWriter writer)
        {
            // ConstrName
            writer.WriteStartElement("Option");
            writer.WriteAttributeString("Key", this.optionName);
            writer.WriteAttributeString("Value", Convert.ToString(this.Value));
            writer.WriteAttributeString("CompareOptionType", this.CompareOptionType.ToString());
            writer.WriteAttributeString("CompareOptionControlType", this.CompareOptionControlType.ToString());
            writer.WriteAttributeString("RowName", this.rowName);
            writer.WriteAttributeString("TableName", this.TableName);
            writer.WriteAttributeString("ErrorMsgId", this.ErrorMsgId);
            writer.WriteAttributeString("ToolTip", this.ToolTip);
            writer.WriteAttributeString("Label", this.Label);
            writer.WriteAttributeString("ErrorMessage", this.ErrorMessage);
            writer.WriteAttributeString("ControlledBy", this.ControlledBy);
            writer.WriteAttributeString("Visible", this.Visible.ToString());
            writer.WriteAttributeString("UIType", this.UIType);
            writer.WriteAttributeString("Reload", this.Reload.ToString());
            writer.WriteAttributeString("Recompare", this.Recompare.ToString());
            writer.WriteAttributeString("RowNumber", this.RowNumber.ToString());

            writer.WriteStartElement("Types");
            if ((this.Types != null) &&
                (this.Types.Length > 0))
            {
                foreach (string type in this.Types)
                {
                    writer.WriteStartElement("Type");
                    writer.WriteAttributeString("Name", type);
                    writer.WriteEndElement(); // type
                }
            }

            writer.WriteEndElement(); // types
            writer.WriteEndElement(); // Option
        }

        #endregion

        #region private methods

        /// <summary>
        /// The check bool value.
        /// </summary>
        /// <param name="value">
        /// The value.
        /// </param>
        /// <param name="typeName">
        /// The type name.
        /// </param>
        /// <returns>
        /// Returns bool value.
        /// </returns>
        /// <exception cref="Exception">
        /// </exception>
        private static bool CheckBoolValue(string value, string typeName)
        {
            bool ret;

            if (!bool.TryParse(value, out ret))
            {
                throw new Exception(string.Format("Invalid {0} value:{1}", typeName, value));
            }

            return ret;
        }

        /// <summary>
        /// The compare option init.
        /// </summary>
        /// <param name="name">
        /// The name.
        /// </param>
        /// <param name="value">
        /// The value.
        /// </param>
        /// <param name="compareOptionType">
        /// The compare option type.
        /// </param>
        /// <param name="errorMsgId">
        /// The error msg id.
        /// </param>
        /// <param name="tableName">
        /// The table name.
        /// </param>
        /// <param name="toolTip">
        /// The tool tip.
        /// </param>
        /// <param name="label">
        /// The label.
        /// </param>
        /// <param name="errorMessage">
        /// The error message.
        /// </param>
        /// <param name="controlledBy">
        /// The controlled by.
        /// </param>
        /// <param name="visible">
        /// The visible.
        /// </param>
        /// <param name="reload">
        /// The reload.
        /// </param>
        /// <param name="recompare">
        /// The recompare.
        /// </param>
        /// <param name="compareOptionControlType">
        /// The compare option control type.
        /// </param>
        /// <param name="uiType">
        /// The ui type.
        /// </param>
        /// <param name="rowNumber">
        /// The row number.
        /// </param>
        private void CompareOptionInit(
            string name, 
            string value, 
            OptionType compareOptionType, 
            string errorMsgId, 
            string tableName, 
            string toolTip, 
            string label, 
            string errorMessage, 
            string controlledBy, 
            string visible, 
            string reload, 
            string recompare, 
            CompareOptionControlType compareOptionControlType, 
            string uiType, 
            int rowNumber)
        {
            this.Init();
            this.optionName = name;
            this.Value = value;
            this.ErrorMsgId = errorMsgId;
            this.TableName = tableName;
            this.rowName = string.Empty;
            this.CompareOptionType = compareOptionType;
            this.ToolTip = toolTip;
            this.Types = this.TableName.Trim().Length > 0 ? this.TableName.Split(new[] {'@'}) : new string[0];

            this.Label = label;
            this.ErrorMessage = errorMessage;
            this.ControlledBy = controlledBy;

            this.Visible = CheckBoolValue(visible, "visible");
            this.Reload = CheckBoolValue(reload, "reload");
            this.Recompare = CheckBoolValue(recompare, "recompare");
            this.UIType = uiType;

            this.CompareOptionControlType = compareOptionControlType;
            this.RowNumber = rowNumber;
        }

        /// <summary>
        /// The init method
        /// </summary>
        private void Init()
        {
            this.Types = new string[0];
            this.Label = string.Empty;
            this.ErrorMessage = string.Empty;
            this.ControlledBy = string.Empty;
            this.Visible = true;
            this.UIType = string.Empty;
            this.Reload = true;
            this.Recompare = true;
            this.TableName = string.Empty;
        }

        #endregion
    }
}